package com.AdvancedDemos.异常;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class LearnException {
    public static void main(String[] args) throws ParseException {
//        Integer.valueOf("abc");//产生异常会抛给JVM虚拟机
        /*产生异常
        Exception in thread "main" java.lang.NumberFormatException: For input string: "abc"
        at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
        at java.base/java.lang.Integer.parseInt(Integer.java:658)
        at java.base/java.lang.Integer.valueOf(Integer.java:989)
        at com.AdvancedDemos.异常.LearnException.main(LearnException.java:5)
        异常名称:NumberFormatException数字格式异常
        产生原因:For input string: "abc"
        产生位置:at com.AdvancedDemos.异常.LearnException.main(LearnException.java:5)
        */
//        int[] arr = {10, 20, 30};
//        System.out.println(arr[3]);
     /*
     Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
     at com.AdvancedDemos.异常.LearnException.main(LearnException.java:17)
     异常名称:ArrayIndexOutOfBoundsException数组下标越界异常
     产生原因:Index 3 out of bounds for length 3
     产生位置:at com.AdvancedDemos.异常.LearnException.main(LearnException.java:17)
     */
//        System.out.println(10 / 0);
        /*Exception in thread "main" java.lang.ArithmeticException: / by zero
	at com.AdvancedDemos.异常.LearnException.main(LearnException.java:25)
	异常名称:ArithmeticException算数异常
	产生原因: / by zero
	产生位置:at com.AdvancedDemos.异常.LearnException.main(LearnException.java:25)*/

        /**
         *                Java异常的体系继承关系图
         *
         *                  Java.lang.Throwable (类)
         *                ↙                      ↘
         *            Error                        Exception
         *                                        ↙           ↘
         *                         RuntimeException        其他异常...
         *                                  ↓
         *                                ......
         *
         * Error代表的是系统级别的错误,属于严重的问题,系统一旦出现问题,sun公司会把这些问题封装成Error对象给出来,说白了,Error是给sun公司自己用的,不是给程序员用的,因此开发人员不用管Error
         * Exception称为异常,它代表的才是程序可能出现的问题,程序员通常会用Exception以及他的子类来封装程序出现的问题
         *
         * Exception分成 运行时异常 与 编译时异常
         * 它一个重要子类叫RuntimeException,在编译阶段不会出现错误提醒,在运行时出现异常(如:ArrayIndexOutOfBoundsException数组下标越界异常,NumberFormatException数字格式异常,ArithmeticException算数异常)
         * 编译时异常是编译时就会出现错误提醒的,(如:日期解析异常)
         * */


        /*try {*/
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date parse = sdf.parse("2028-11-11 19:24:23");//编译时异常,直接报红,未处理 异常: java.text.ParseException
        //解决办法:
        // ①用try catch块包围以抓取可能产生的异常,
        /*
         * try{
         * //可能出现异常的代码段
         * }catch(异常类型1 变量){
         * //处理异常1
         * }catch(异常类型2 变量){
         * //处理异常2
         * }...
         * */
        //或者
        // ②用throws抛出可能产生的异常给上层调用者(main方法的上层调用者是JVM虚拟机,JVM不知道如何处理异常就会用try catch抓住异常,控制台报出异常)
        /*
         * 方法 throws 异常1,异常2,异常3{
         * //方法体
         * ...
         * }
         * */
        System.out.println(parse);
        /*} catch (ParseException e) {
            e.printStackTrace();
        }*/

/////////////////////////////////////////////////////////////////////////////////
        //需求:保存一个合法的年龄
        //测试运行时异常
        try {
            saveAge(160);//如果输入不符合要求该函数会抛出AgeIllegalRuntimeException异常
            System.out.println("底层执行成功!");
        } catch (Exception e) {
//            e.printStackTrace();
            System.out.println(e.getMessage());
            System.out.println("底层出现了Bug!");//抛出异常后会打印
        }
        /*com.AdvancedDemos.异常.AgeIllegalRuntimeException: 年龄非法,你的年龄是:160
	at com.AdvancedDemos.异常.LearnException.saveAge(LearnException.java:100)
	at com.AdvancedDemos.异常.LearnException.main(LearnException.java:86)
底层出现了Bug!*/


        //测试编译时异常
        try {
            saveAge2(161);
            System.out.println("底层执行成功!");
        } catch (编译时异常 e) {
//            e.printStackTrace();
            System.out.println(e.getMessage());
            System.out.println("底层出现了Bug!");//抛出异常后会打印
        }
        /*com.AdvancedDemos.异常.编译时异常: 年龄非法,你的年龄是:161
	at com.AdvancedDemos.异常.LearnException.saveAge2(LearnException.java:123)
	at com.AdvancedDemos.异常.LearnException.main(LearnException.java:99)
底层出现了Bug!
*/

    }

    public static void saveAge(int age) {
        if (age > 0 && age < 150) {
            System.out.println("年龄保存成功:" + age);
        } else {
            //表示输入非法,应该抛出异常
            throw new AgeIllegalRuntimeException("年龄非法,你的年龄是:" + age);//新建自定义异常类对象,并且用关键字throw抛出
        }
    }


    public static void saveAge2(int age) throws 编译时异常 {//编译时异常要么自己方法内try catch处理掉,要么用throws标记,告诉上层自己会抛出什么异常
        if (age > 0 && age < 150) {
            System.out.println("年龄保存成功:" + age);
        } else {
            //表示输入非法,应该抛出异常
            throw new 编译时异常("年龄非法,你的年龄是:" + age);//新建自定义异常类对象,并且用关键字throw抛出
        }
    }

}

/**
 * 自定义异常类:
 * <p>
 * ① 自定义运行时异常
 * 定义一个异常类继承RuntimeException
 * 重写构造器
 * 通过throw new 异常类(XXX) 来创建异常对象并抛出
 * 编译阶段不报错,提醒不强烈,运行时才可能出现!
 * <p>
 * ② 自定义编译时异常
 * 定义一个异常类继承Exception
 * 重写构造器
 * 通过throw new 异常类(XXX) 来创建异常对象并抛出
 * 编译阶段就报错,提醒更加强烈!
 */

class AgeIllegalRuntimeException extends RuntimeException {
    public AgeIllegalRuntimeException() {
    }

    public AgeIllegalRuntimeException(String message) {
        super(message);//message用于存放当前异常的原因,然后送到了父类RuntimeException的有参构造函数中
    }
}

class 编译时异常 extends Exception {
    public 编译时异常() {
    }

    public 编译时异常(String message) {
        super(message);
    }
}


